﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Linq.Expressions;
using NRemedy;
using System.Text;
using System.Web.Routing;
using System.Web.WebPages;


namespace NRemedy.MVC.UI
{
    public static class NRemedyUIExtension
    {
        public const string FormModelKey = "formmodel";

        #region menu

        public static MvcHtmlString MenuFor<TModel, TValue>(this HtmlHelper<TModel> html,
            Expression<Func<TModel, TValue>> expression,
            MenuObject MenuObject,
            object eventChainCallback,
            object htmlAttributes,
            bool ignoreFormModel
            )
        {
            //ExpressionHelper是mvc自带的从表达式中获取属性的helper，还没具体研究实现
            string propertyName = ExpressionHelper.GetExpressionText(expression);

            ITypeMetaProvider<TModel> modelProvider = new DefaultTypeMetaProvider<TModel>();

            var properties = modelProvider.GetPropertyInfoes(
                System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.GetProperty,
                null);

            var property = properties.FirstOrDefault(p => p.Property.Name == propertyName);

            if (property == null)
                throw new MemberAccessException("propertyName");
            
            //get additional html attributes
            var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
            var callback = HtmlHelper.AnonymousObjectToHtmlAttributes(eventChainCallback);

            //eval the property value
             TValue v = default(TValue);
            if (html.ViewData.Model != null)
            {
                Func<TModel, TValue> func = expression.Compile();
                v = func(html.ViewData.Model);
            }

            //TagBuilder impelement HttpUtility.HtmlAttributeEncode
            RawTagBuilder tagb = new RawTagBuilder("input");
            //tagb.MergeAttribute("class","easyui-combobox");
            tagb.AddCssClass("easyui-combobox");
            tagb.MergeAttribute("editable", dictionary.ContainsKey("editable") ? dictionary["editable"].ToString(): "false" );
            tagb.MergeAttribute("arname", propertyName);
            tagb.MergeAttribute("name",propertyName);
            tagb.MergeAttribute("id",property.DatabaseId.ToString());
            tagb.MergeAttribute("artype",property.DatabaseType.ToString());
            //获取属性本来的值，并设置input的oval和value
            tagb.MergeAttribute("oval",v == null ? string.Empty : v.ToString());
            tagb.MergeAttribute("value",v == null ? string.Empty : v.ToString());

            DataOptionBuilder optionb = new DataOptionBuilder();
            optionb.MergeAttribute("valueField", "v");
            optionb.MergeAttribute("textField", "t");
            optionb.MergeAttribute("panelHeight", dictionary.ContainsKey("panelHeight") ? dictionary["panelHeight"].ToString() : "auto");
            optionb.MergeAttribute("method", dictionary.ContainsKey("method") ? dictionary["method"].ToString() : "Get");
            optionb.MergeAttribute("url", MenuObject.GetMenuUrl());
            
            //onSelect
            string defaultSelect = string.Empty;
            if (callback.ContainsKey("onSelect"))
                defaultSelect += callback["onSelect"] + "($(this),rec);";
            if (MenuObject.GetImpacts() != null)
            {
                foreach (var impact_id in MenuObject.GetImpacts())
                {
                    defaultSelect += string.Format("$('#{0}').combobox('clear').combobox('reload');", impact_id);
                }
            }
            if (defaultSelect != string.Empty){
                optionb.MergeCallback("onSelect", "function(rec){ " + defaultSelect + " }");
            }
            
            //onBeforeLoad
            string defaultBeforeLoad = string.Empty;
            if (!string.IsNullOrEmpty(MenuObject.Qualification))
                defaultBeforeLoad += "rebuildMenuParam($(this),param);";
            if (callback.ContainsKey("onBeforeLoad"))
                defaultBeforeLoad += callback["onBeforeLoad"] + "($(this),param);";
            if (defaultBeforeLoad != string.Empty)
            {
                optionb.MergeCallback("onBeforeLoad", "function(param){ " + defaultBeforeLoad + " }");
            }


            tagb.MergeAttribute("data-options", optionb.ToString());
            if (!string.IsNullOrEmpty(MenuObject.Qualification))
                tagb.MergeAttribute("qualification", MenuObject.Qualification.ToHtmlSafeString());

            FormModel currentModel = GetFormModel(html);

            //htmlattribute
            if (dictionary != null){
                foreach (var d in dictionary){
                    if (d.Key == "class")
                        tagb.AddCssClass(d.Value.ToString());
                    else
                    {
                        if (currentModel == FormModel.Search //if in search model
                            && (string.Compare(d.Key, "readonly", true) == 0 //igonre readonly
                            || string.Compare(d.Key, "disabled", true) == 0 //ignore disabled
                            ))
                        {
                            continue;
                        }
                        tagb.MergeAttribute(d.Key, d.Value.ToString());
                    }
                }
            }

            return MvcHtmlString.Create(tagb.ToString(TagRenderMode.SelfClosing));
        }

        public static MvcHtmlString MenuFor<TModel, TValue>(this HtmlHelper<TModel> html,
             Expression<Func<TModel, TValue>> expression,
             MenuObject MenuObject,
            object eventChainCallback,
            object htmlAttributes
        )
        {
            return MenuFor<TModel, TValue>(html, expression, MenuObject, eventChainCallback, htmlAttributes, false);
        }

        public static MvcHtmlString MenuFor<TModel, TValue>(this HtmlHelper<TModel> html,
            Expression<Func<TModel, TValue>> expression,
            MenuObject MenuObject
            )
        {
            return MenuFor<TModel, TValue>(html, expression, MenuObject,  null, null,false);
        }

        #endregion

        //public static MvcHtmlString InputFor<TModel, TValue>(this HtmlHelper<TModel> html,
        //    Expression<Func<TModel, TValue>> expression,
        //    //PermissionInputList permission,
        //    object htmlAttributes
        //    )
        //{
        //    string propertyName = ExpressionHelper.GetExpressionText(expression);
        //    ITypeMetaProvider<TModel> modelProvider = new DefaultTypeMetaProvider<TModel>();

        //    var properties = modelProvider.GetPropertyInfoes(
        //        System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.GetProperty,
        //        null);

        //    var property = properties.FirstOrDefault(p => p.Property.Name == propertyName);

        //    if (property == null)
        //        throw new MemberAccessException("propertyName");

        //    //get additional html attributes
        //    var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

        //    //eval the property value
        //    TValue v = default(TValue);
        //    if (html.ViewData.Model != null)
        //    {
        //        Func<TModel, TValue> func = expression.Compile();
        //        v = func(html.ViewData.Model);
        //    }

        //    RawTagBuilder tagb = new RawTagBuilder("input");

        //    tagb.MergeAttribute("arname", propertyName);//jquery easy ui will delete name,so here arname store the name
        //    tagb.MergeAttribute("name", propertyName);
        //    tagb.MergeAttribute("id", property.DatabaseId.ToString());
        //    tagb.MergeAttribute("artype", property.DatabaseType.ToString());

        //    //获取属性本来的值，并设置input的oval和value
        //    tagb.MergeAttribute("oval", v == null ? string.Empty : v.ToString());
        //    tagb.MergeAttribute("value", v == null ? string.Empty : v.ToString());

        //    //htmlattribute
        //    if (dictionary != null)
        //    {
        //        foreach (var d in dictionary)
        //        {
        //            tagb.MergeAttribute(d.Key, d.Value.ToString());
        //        }
        //    }

        //    return MvcHtmlString.Create(tagb.ToString(TagRenderMode.SelfClosing));
        //}


        #region  input

        public static MvcHtmlString InputFor<TModel, TValue>(this HtmlHelper<TModel> html,
                Expression<Func<TModel, TValue>> expression, //property selector
                object htmlAttributes,   //additional html attribute
                bool ignoreFormModel
            )
        {
            string propertyName = ExpressionHelper.GetExpressionText(expression);
            ITypeMetaProvider<TModel> modelProvider = new DefaultTypeMetaProvider<TModel>();

            var properties = modelProvider.GetPropertyInfoes(
                System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.GetProperty,
                null);

            var property = properties.FirstOrDefault(p => p.Property.Name == propertyName);

            if (property == null)
                throw new MemberAccessException("propertyName");
            //get additional html attributes
            var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

            //eval the property value
            TValue v = default(TValue);
            if (html.ViewData.Model != null)
            {
                Func<TModel, TValue> func = expression.Compile();
                v = func(html.ViewData.Model);
            }

            RawTagBuilder tagb = new RawTagBuilder("input");

            tagb.MergeAttribute("arname", propertyName);//jquery easy ui will delete name,so here arname store the name
            tagb.MergeAttribute("name", propertyName);
            tagb.MergeAttribute("id", property.DatabaseId.ToString());
            tagb.MergeAttribute("artype", property.DatabaseType.ToString());

            //获取属性本来的值，并设置input的oval和value
            tagb.MergeAttribute("oval", v == null ? string.Empty : v.ToString());
            tagb.MergeAttribute("value", v == null ? string.Empty : v.ToString());

            //check the form model
            FormModel currentModel = GetFormModel(html);


            //htmlattribute
            if (dictionary != null)
            {
                foreach (var d in dictionary)
                {
                    if (d.Key == "class")
                        tagb.AddCssClass(d.Value.ToString());
                    else
                    {
                        if (currentModel == FormModel.Search //if in search model
                            && (string.Compare(d.Key, "readonly", true) == 0 //igonre readonly
                            || string.Compare(d.Key, "disabled", true) == 0 //ignore disabled
                            ))
                        {
                            continue;
                        }
                        tagb.MergeAttribute(d.Key, d.Value.ToString());
                    }
                }
            }

            return MvcHtmlString.Create(tagb.ToString(TagRenderMode.SelfClosing));
        }

        public static MvcHtmlString InputFor<TModel, TValue>(this HtmlHelper<TModel> html,
                Expression<Func<TModel, TValue>> expression //property selector
            )
        {
            return InputFor<TModel, TValue>(html,expression,null,false);
        }

        public static MvcHtmlString InputFor<TModel, TValue>(this HtmlHelper<TModel> html,
                Expression<Func<TModel, TValue>> expression, //property selector
                object htmlAttributes   //additional html attribute
            )
        {
            return InputFor<TModel, TValue>(html, expression, htmlAttributes, false);
        }

        #endregion

        #region textarea

        public static MvcHtmlString TextAreaFor<TModel, TValue>(this HtmlHelper<TModel> html,
                Expression<Func<TModel, TValue>> expression, //property selector
                object htmlAttributes,   //additional html attribute
                bool ignoreFormModel
            )
        {
            string propertyName = ExpressionHelper.GetExpressionText(expression);
            ITypeMetaProvider<TModel> modelProvider = new DefaultTypeMetaProvider<TModel>();

            var properties = modelProvider.GetPropertyInfoes(
                System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.GetProperty,
                null);

            var property = properties.FirstOrDefault(p => p.Property.Name == propertyName);

            if (property == null)
                throw new MemberAccessException("propertyName");
            //get additional html attributes
            var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

            //eval the property value
            TValue v = default(TValue);
            if (html.ViewData.Model != null)
            {
                Func<TModel, TValue> func = expression.Compile();
                v = func(html.ViewData.Model);
            }

            RawTagBuilder tagb = new RawTagBuilder("textarea");

            tagb.MergeAttribute("arname", propertyName);//jquery easy ui will delete name,so here arname store the name
            tagb.MergeAttribute("name", propertyName);
            tagb.MergeAttribute("id", property.DatabaseId.ToString());
            tagb.MergeAttribute("artype", property.DatabaseType.ToString());

            //获取属性本来的值，并设置input的oval和value
            tagb.MergeAttribute("oval", v == null ? string.Empty : v.ToString());
            //tagb.MergeAttribute("value", v == null ? string.Empty : v.ToString());

            //check the form model
            FormModel currentModel = GetFormModel(html);


            //htmlattribute
            if (dictionary != null){
                foreach (var d in dictionary)
                {
                    if (d.Key == "class")
                        tagb.AddCssClass(d.Value.ToString());
                    else
                    {
                        if (currentModel == FormModel.Search //if in search model
                            && (string.Compare(d.Key, "readonly", true) == 0 //igonre readonly
                            || string.Compare(d.Key, "disabled", true) == 0 //ignore disabled
                            ))
                        {
                            continue;
                        }
                        tagb.MergeAttribute(d.Key, d.Value.ToString());
                    }
                }
            }

            tagb.InnerHtml = v == null ? string.Empty : v.ToString();

            return MvcHtmlString.Create(tagb.ToString(TagRenderMode.Normal));
        }

        public static MvcHtmlString TextAreaFor<TModel, TValue>(this HtmlHelper<TModel> html,
               Expression<Func<TModel, TValue>> expression //property selector
           )
        {
            return TextAreaFor<TModel, TValue>(html, expression, null, false);
        }

        public static MvcHtmlString TextAreaFor<TModel, TValue>(this HtmlHelper<TModel> html,
                Expression<Func<TModel, TValue>> expression, //property selector
                object htmlAttributes   //additional html attribute
            )
        {
            return TextAreaFor<TModel, TValue>(html, expression, htmlAttributes, false);
        }

        #endregion

        //get form model, default : detail model
        public static FormModel GetFormModel<TModel>(this HtmlHelper<TModel> html)
        {
            if (html.ViewContext.RouteData.Values[NRemedyUIExtension.FormModelKey] != null)
            {
                if (html.ViewContext.RouteData.Values[NRemedyUIExtension.FormModelKey].ToString() == "Search")
                {
                    return FormModel.Search;
                }
                else if (html.ViewContext.RouteData.Values[NRemedyUIExtension.FormModelKey].ToString() == "Create")
                {
                    return FormModel.Create;
                }
            }
            return FormModel.Detail;
        }

    }
}
